---
title: Running agents
description: Configure and execute agent workflows with the Runner class
---

import { Aside, Code } from '@astrojs/starlight/components';
import helloWorldWithRunnerExample from '../../../../../examples/docs/hello-world-with-runner.ts?raw';
import helloWorldExample from '../../../../../examples/docs/hello-world.ts?raw';
import runningAgentsExceptionExample from '../../../../../examples/docs/running-agents/exceptions1.ts?raw';
import chatLoopExample from '../../../../../examples/docs/running-agents/chatLoop.ts?raw';
import conversationIdExample from '../../../../../examples/docs/running-agents/conversationId.ts?raw';
import previousResponseIdExample from '../../../../../examples/docs/running-agents/previousResponseId.ts?raw';

Agents do nothing by themselves – you **run** them with the `Runner` class or the `run()` utility.

<Code lang="typescript" code={helloWorldExample} title="Simple run" />

When you don't need a custom runner, you can also use the `run()` utility, which runs a singleton default `Runner` instance.

Alternatively, you can create your own runner instance:

<Code lang="typescript" code={helloWorldWithRunnerExample} title="Simple run" />

After running your agent, you will receive a [result](/openai-agents-js/guides/results) object that contains the final output and the full history of the run.

## The agent loop

When you use the run method in Runner, you pass in a starting agent and input. The input can either be a string (which is considered a user message), or a list of input items, which are the items in the OpenAI Responses API.

The runner then runs a loop:

1. Call the current agent’s model with the current input.
2. Inspect the LLM response.
   - **Final output** → return.
   - **Handoff** → switch to the new agent, keep the accumulated conversation history, go to 1.
   - **Tool calls** → execute tools, append their results to the conversation, go to 1.
3. Throw [`MaxTurnsExceededError`](/openai-agents-js/openai/agents-core/classes/maxturnsexceedederror) once `maxTurns` is reached.

<Aside type="note">
  The rule for whether the LLM output is considered as a "final output" is that
  it produces text output with the desired type, and there are no tool calls.
</Aside>

### Runner lifecycle

Create a `Runner` when your app starts and reuse it across requests. The instance
stores global configuration such as model provider and tracing options. Only
create another `Runner` if you need a completely different setup. For simple
scripts you can also call `run()` which uses a default runner internally.

## Run arguments

The input to the `run()` method is an initial agent to start the run on, input for the run and a set of options.

The input can either be a string (which is considered a user message), or a list of [input items](/openai-agents-js/openai/agents-core/type-aliases/agentinputitem), or a [`RunState`](/openai-agents-js/openai/agents-core/classes/runstate) object in case you are building a [human-in-the-loop](/openai-agents-js/guides/human-in-the-loop) agent.

The additional options are:

| Option     | Default | Description                                                                                                                        |
| ---------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `stream`   | `false` | If `true` the call returns a `StreamedRunResult` and emits events as they arrive from the model.                                   |
| `context`  | –       | Context object forwarded to every tool / guardrail / handoff. Learn more in the [context guide](/openai-agents-js/guides/context). |
| `maxTurns` | `10`    | Safety limit – throws [`MaxTurnsExceededError`](/openai-agents-js/openai/agents-core/classes/maxturnsexceedederror) when reached.  |
| `signal`   | –       | `AbortSignal` for cancellation.                                                                                                    |

## Streaming

Streaming allows you to additionally receive streaming events as the LLM runs. Once the stream is started, the `StreamedRunResult` will contain the complete information about the run, including all the new outputs produces. You can iterate over the streaming events using a `for await` loop. Read more in the [streaming guide](/openai-agents-js/guides/streaming).

## Run config

If you are creating your own `Runner` instance, you can pass in a `RunConfig` object to configure the runner.

| Field                       | Type                  | Purpose                                                                                          |
| --------------------------- | --------------------- | ------------------------------------------------------------------------------------------------ |
| `model`                     | `string \| Model`     | Force a specific model for **all** agents in the run.                                            |
| `modelProvider`             | `ModelProvider`       | Resolves model names – defaults to the OpenAI provider.                                          |
| `modelSettings`             | `ModelSettings`       | Global tuning parameters that override per‑agent settings.                                       |
| `handoffInputFilter`        | `HandoffInputFilter`  | Mutates input items when performing handoffs (if the handoff itself doesn’t already define one). |
| `inputGuardrails`           | `InputGuardrail[]`    | Guardrails applied to the _initial_ user input.                                                  |
| `outputGuardrails`          | `OutputGuardrail[]`   | Guardrails applied to the _final_ output.                                                        |
| `tracingDisabled`           | `boolean`             | Disable OpenAI Tracing completely.                                                               |
| `traceIncludeSensitiveData` | `boolean`             | Exclude LLM/tool inputs & outputs from traces while still emitting spans.                        |
| `workflowName`              | `string`              | Appears in the Traces dashboard – helps group related runs.                                      |
| `traceId` / `groupId`       | `string`              | Manually specify the trace or group ID instead of letting the SDK generate one.                  |
| `traceMetadata`             | `Record<string, any>` | Arbitrary metadata to attach to every span.                                                      |

## Conversations / chat threads

Each call to `runner.run()` (or `run()` utility) represents one **turn** in your application-level conversation. You choose how much of the `RunResult` you show the end‑user – sometimes only `finalOutput`, other times every generated item.

<Code
  lang="typescript"
  code={chatLoopExample}
  title="Example of carrying over the conversation history"
/>

See [the chat example](https://github.com/openai/openai-agents-js/tree/main/examples/basic/chat.ts) for an interactive version.

### Server-managed conversations

You can let the OpenAI Responses API persist conversation history for you instead of sending your entire local transcript on every turn. This is useful when you are coordinating long conversations or multiple services. See the [Conversation state guide](https://platform.openai.com/docs/guides/conversation-state?api-mode=responses) for details.

OpenAI exposes two ways to reuse server-side state:

#### 1. `conversationId` for an entire conversation

You can create a conversation once using [Conversations API](https://platform.openai.com/docs/api-reference/conversations/create) and then reuse its ID for every turn. The SDK automatically includes only the newly generated items.

<Code
  lang="typescript"
  code={conversationIdExample}
  title="Reusing a server conversation"
/>

#### 2. `previousResponseId` to continue from the last turn

If you want to start only with Responses API anyway, you can chain each request using the ID returned from the previous response. This keeps the context alive across turns without creating a full conversation resource.

<Code
  lang="typescript"
  code={previousResponseIdExample}
  title="Chaining with previousResponseId"
/>

## Exceptions

The SDK throws a small set of errors you can catch:

- [`MaxTurnsExceededError`](/openai-agents-js/openai/agents-core/classes/maxturnsexceedederror) – `maxTurns` reached.
- [`ModelBehaviorError`](/openai-agents-js/openai/agents-core/classes/modelbehaviorerror) – model produced invalid output (e.g. malformed JSON, unknown tool).
- [`InputGuardrailTripwireTriggered`](/openai-agents-js/openai/agents-core/classes/inputguardrailtripwiretriggered) / [`OutputGuardrailTripwireTriggered`](/openai-agents-js/openai/agents-core/classes/outputguardrailtripwiretriggered) – guardrail violations.
- [`GuardrailExecutionError`](/openai-agents-js/openai/agents-core/classes/guardrailexecutionerror) – guardrails failed to complete.
- [`ToolCallError`](/openai-agents-js/openai/agents-core/classes/toolcallerror) – any of function tool calls failed.
- [`UserError`](/openai-agents-js/openai/agents-core/classes/usererror) – any error thrown based on configuration or user input.

All extend the base `AgentsError` class, which could provide the `state` property to access the current run state.

Here is an example code that handles `GuardrailExecutionError`:

<Code
  lang="typescript"
  code={runningAgentsExceptionExample}
  title="Guardrail execution error"
/>

When you run the above example, you will see the following output:

```
Guardrail execution failed: Error: Input guardrail failed to complete: Error: Something is wrong!
Math homework guardrail tripped
```

---

## Next steps

- Learn how to [configure models](/openai-agents-js/guides/models).
- Provide your agents with [tools](/openai-agents-js/guides/tools).
- Add [guardrails](/openai-agents-js/guides/guardrails) or [tracing](/openai-agents-js/guides/tracing) for production readiness.
